0%

MySQL Binlog(五)——MySQL常见binlog event解析(上)

MySQL Binlog(五)——MySQL常见binlog event解析(上)

前言

前面讲了binlog event的基础知识,从这篇文章开始我们就具体来解析binlog中常见的event,了解其具体代表的意义。本文会介绍Format_description_event、Rotate_event、Query_log_event、Rows_query_log_event几种event。

Format_description_event

Format_description_event是每个binlog文件开头的一个描述信心的event。

post-header部分

字段 字节数 描述
binlog_version 2字节 binlog结构的版本,v1,v2,v4
server_version 50字节 MySQL server的数据库版本
timestamp 4字节 创建该binlog文件的时间,单位为秒
header_length 1字节 指定公共头部的长度,v4版本中这个值一直为19,说明其他所有的event的extra_header部分都是空,extra_header长度为header_length-19
event_post_header_length variable size,跟各个版本支持的event类型总数一致 每个event类型,占用一个字节,表示该event类型post-header部分的长度

event-body部分

字节解析示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
公共头部部分省略
04 00 //binlog_version :v4版本
35 2e 36 2e 33 34 2d 6c 6f 67
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 //mysql server version :16进制转换为ascii之后,值为5.6.34-log
00 00 00 00 //timestamp:
13 //header length :19,说明该版本的event类型公共头部长度都为19,extra_header长度为header_length-19
38 0d 00 08 00 12 00 04 04 04
04 12 00 00 5c 00 04 1a 08 00
00 00 08 08 08 02 00 00 00 0a
0a 0a 19 19 00 //event_post_header_len:各个类型event的post-header部分长度
01 2e ef 23 e2

Rotate_event

当MySQL切换至新的binlog文件的时候,MySQL会在旧的binlog文件中写入一个ROTATE_EVENT,其内容包含新的binlog文件的文件名以及第一个偏移地址。当在数据库中执行FLUSH LOGS语句或者binlog文件的大小超过max_binlog_size参数设定的值就会切换新的binlog文件。

post-header部分

字段 字节数 描述
next_binlog_po 8字节 下一个binlog文件起始的偏移地址

event-body部分

字段 字节数 描述
next_binlog_filename variable string 下一个binlog文件的文件名

字节解析示例

1
2
3
4
公共头部部分省略
04 00 00 00 00 00 00 00 //next_binlog_pos:下一个binlog的起始偏移地址,小端存储,16进制转换为10进制之后为4
6d 79 73 71 6c 2d 62 69 6e 2e 30 30 30 30 30 32 //next_binlog_filename:下一个binlog的文件名,16进制转换为ascii之后,值为mysql-bin.000002
b3 db 0b 9a checksum

Query_log_event

记录更新操作的语句。

post-header部分

字段 字节数 描述
thread_id 4字节 小端存储,执行语句的线程ID号
exec_time 4字节 小端存储,语句执行的时间
db_len 1字节 database名的长度
error_code 2字节 错误号
status_vars_len 2字节 小端存储,这部分,在v1和v3版本的event中是没有的,指定状态值的长度

event-body部分

字段 字节数 描述
status_vars status_vars_len字节 记录状态值,具体的解析见下表
database_name db_len+1字节 null-terminaled类型的字符串,记录database的名字
query_statement 不定 执行的语句
check_sum 4字节 校验码

status_vars的解析是,一个字节表示状态的类型,在类型之后按照类型不同紧接着不同字节数的状态值,状态的类型一共有:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum Query_event_status_vars
{
Q_FLAGS2_CODE= 0,
Q_SQL_MODE_CODE,
Q_CATALOG_CODE,
Q_AUTO_INCREMENT,
Q_CHARSET_CODE,
Q_TIME_ZONE_CODE,
Q_CATALOG_NZ_CODE,
Q_LC_TIME_NAMES_CODE,
Q_CHARSET_DATABASE_CODE,
Q_TABLE_MAP_FOR_UPDATE_CODE,
Q_MASTER_DATA_WRITTEN_CODE,
Q_INVOKER,
Q_UPDATED_DB_NAMES,
Q_MICROSECONDS,
Q_COMMIT_TS,
Q_COMMIT_TS2,
Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP
};

不同状态对应的状态值的字节数

状态 对用的code 状态值占用的字节数
Q_FLAGS2_CODE 0 4字节
Q_SQL_MODE_CODE 1 8字节
Q_CATALOG_CODE 2 第一个字节表示catalog_len,总共catalog_len+2个字节
Q_AUTO_INCREMENT 3 4字节
Q_CHARSET_CODE 4 6字节
Q_TIME_ZONE_CODE 5 第一个字节表示time_zone_len,总共time_zone_len+1字节
Q_CATALOG_NZ_CODE 6 第一个字节表示catalog_len,总共catalog_len+1个字节
Q_LC_TIME_NAMES_CODE 7 2字节
Q_CHARSET_DATABASE_CODE 8 2字节
Q_TABLE_MAP_FOR_UPDATE_CODE 9 8字节
Q_MASTER_DATA_WRITTEN_CODE 10 4字节
Q_INVOKER 11 包含两部分,一部分是user,一部分是host。user部分,一个字节表示user_len,接着user_len个字节表示user。host部分,一个字节表示host_len,接着host_len个字节表示host。
Q_UPDATED_DB_NAMES 12
Q_MICROSECONDS 13 3字节
Q_COMMIT_TS 14
Q_COMMIT_TS2 15
Q_EXPLICIT_DEFAULTS_FOR_TIMESTAMP 16 1字节

字节解析示例

执行语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
insert into test1(`name`) values('beijing');

root@localhost : (none) 06:07:04> show binlog events in 'mysql-bin.000012';
+------------------+-----+-------------+-----------+-------------+-------------------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+-------------+-----------+-------------+-------------------------------------------------------------+
| mysql-bin.000012 | 4 | Format_desc | 330619 | 120 | Server ver: 5.6.34-log, Binlog ver: 4 |
| mysql-bin.000012 | 120 | Query | 330619 | 212 | BEGIN |
| mysql-bin.000012 | 212 | Intvar | 330619 | 244 | INSERT_ID=28 |
| mysql-bin.000012 | 244 | Query | 330619 | 374 | use `gangshen`; insert into test1(`name`) values('beijing') |
| mysql-bin.000012 | 374 | Xid | 330619 | 405 | COMMIT /* xid=2961 */ |
+------------------+-----+-------------+-----------+-------------+-------------------------------------------------------------+
5 rows in set (0.00 sec)

使用mysqlbinlog工具解析binlog文件

1
2
3
4
5
6
7
8
9
# at 244
#180105 15:20:29 server id 330619 end_log_pos 244 CRC32 0xf41b5eaa Intvar
SET INSERT_ID=28/*!*/;
#180105 15:20:29 server id 330619 end_log_pos 374 CRC32 0x98379221 Query thread_id=106404 exec_time=0 error_code=0
use `gangshen`/*!*/;
SET TIMESTAMP=1515183629/*!*/;
insert into test1(`name`) values('beijing')
/*!*/;
# at 374

解析二进制文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
公共头部部分省略。。。。
a4 9f 01 00 //thread_id:执行语句的线程号,小端存储,转换为16进制为106404
00 00 00 00 //exec_time:执行语句的时间,小端存储,转化为16进制为0
08 //db_len:database name的长度,转换为10进制为8
00 00 //error_code:错误号,小端存储,转换为10进制为0
2a 00 //status_vars_len:状态值的长度,小端存储,转换为10进制为42,表示后续的42个字节为状态值的内容
//status_vars_len
00 00 00 00 00
01 00 00 20 40 00 00 00 00
06 03 73 74 64
03 02 00 02 00
04 21 00 21 00 53 00
0c 01 67 61 6e 67 73 68 65 6e 00
67 61 6e 67 73 68 65 6e 00 //database_name:数据库名称,null-terminaled string类型 ,转换为字符串为gangshen
696e7365727420696e746f20746573743128606e616d6560292076616c75657328276265696a696e672729 //query_statement:执行的语句,转换为字符串为:insert into test1(`name`) values('beijing')
21 92 37 98//checksum

Rows_query_log_event

在row格式复制模式下,将query以语句形式记录。在5.6.2版本之后,可以通过设置binlog_rows_query_log_events参数来控制在row格式复制模式下是否需要将query语句记录到binlog文件中。

post-header部分

event-body部分

字段 字节数 描述
str_len 1字节 记录语句长度
statement str_len字节 对应的语句
checksum 4字节 校验码

字节解析示例

执行语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@localhost : gangshen 09:11:56> insert into test1(`name`) values('rows_query');
Query OK, 1 row affected (0.04 sec)

root@localhost : gangshen 09:12:06> show binlog events in 'mysql-bin.000014';
+------------------+-----+-------------+-----------+-------------+--------------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+-------------+-----------+-------------+--------------------------------------------------+
| mysql-bin.000014 | 4 | Format_desc | 330619 | 120 | Server ver: 5.6.34-log, Binlog ver: 4 |
| mysql-bin.000014 | 120 | Query | 330619 | 201 | BEGIN |
| mysql-bin.000014 | 201 | Rows_query | 330619 | 271 | # insert into test1(`name`) values('rows_query') |
| mysql-bin.000014 | 271 | Table_map | 330619 | 326 | table_id: 98 (gangshen.test1) |
| mysql-bin.000014 | 326 | Write_rows | 330619 | 377 | table_id: 98 flags: STMT_END_F |
| mysql-bin.000014 | 377 | Xid | 330619 | 408 | COMMIT /* xid=3032 */ |
+------------------+-----+-------------+-----------+-------------+--------------------------------------------------+
6 rows in set (0.00 sec)

使用mysqlbinlog工具解析binlog文件

1
2
3
4
# at 201
#180108 9:12:06 server id 330619 end_log_pos 271 CRC32 0xdc68af8a Rows_query
# insert into test1(`name`) values('rows_query')
# at 271

解析二进制文件:

1
2
3
4
公共头部部分省略。。。
2e //str_len:执行语句的长度,转换为10进制为46
696e7365727420696e746f20746573743128606e616d6560292076616c7565732827726f77735f71756572792729 //statement:执行的语句,转换为ascii为insert into test1(`name`) values('rows_query')
8a af 68 dc //check_sum

参考链接